﻿/*文件注释
 * ===============================================================================
 * 说明：
 * 作者：曾永佑
 * 版本：V1.0
 * 创建日期：2013-03-10
 * 完成日期： 
 * 修改纪录：  
 * ===============================================================================
 */  
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;  
using SRF.Security.Principal;
using SRF.Security.Permission;
using SRF.Security.DataRule;
using System.Web.Security;

namespace SRF.Security
{
    public class SecurityProvider : System.Configuration.Provider.ProviderBase, ISecurityProvider
    {
        readonly string UIPermissionKey = "_uipermission_";
        readonly string UrlPermissionKey = "_urlpermission_";
        readonly string DataRuleKey = "_datarule_";

        #region

        public virtual IUser GetCurrentUser()
        {
            IUser user = null;
            HttpCookie cookie = System.Web.HttpContext.Current.Request.Cookies[System.Web.Security.FormsAuthentication.FormsCookieName];
            if (cookie != null && !string.IsNullOrEmpty(cookie.Value))
            {
                System.Web.Security.FormsAuthenticationTicket ticket = System.Web.Security.FormsAuthentication.Decrypt(cookie.Value);
                if (ticket != null && string.IsNullOrEmpty(ticket.UserData) == false)
                    System.Web.HttpContext.Current.User = user = (new System.Web.Script.Serialization.JavaScriptSerializer()).Deserialize<SRF.Security.Principal.User>(ticket.UserData);
            }

            return user;
        }

        public virtual IUser GetUser(string loginId)
        {
            return MembershipFactory.Provider.GetUser(loginId);
        }

        public virtual void Login(string loginId = "", string password = "", string code = "")
        {
            IUser user = GetUser(loginId);
            if (user != null)
            {
                if (NeedEncrypt)
                    password = Encrypt(password);

                if (user.Password == password)
                {
                    SetAuthCookie(user);
                    RemovePromissionSession();
                }
                else
                {
                    throw new Exceptions.PasswordWrongException();
                }
            }
            else
                throw new Exceptions.UserNotFoundException();
        }

        public virtual void Logout()
        {
            System.Web.Security.FormsAuthentication.SignOut();
            RemovePromissionSession();
        }

        public virtual void ChangePassword(string loginId, string newPassword, string oldPassword = "")
        {
            string password = NeedEncrypt ? Encrypt(newPassword) : newPassword;

            if (!string.IsNullOrEmpty(oldPassword))
            {
                if (!MembershipFactory.Provider.VerifyPassword(loginId, Encrypt(oldPassword)))
                {
                    throw new Exceptions.PasswordWrongException();
                }
            }

            MembershipFactory.Provider.ChangePassword(loginId, password);
        }

        public bool HasActionGrant(string action)
        {
            if (IsLogin && !string.IsNullOrEmpty(action))
            {
                IEnumerable<Permission.UIPermission> uiPermissions;
                if (HttpContext.Current.Session != null && HttpContext.Current.Session[UIPermissionKey] != null)
                {
                    uiPermissions = (IEnumerable<Permission.UIPermission>)HttpContext.Current.Session[UIPermissionKey];
                }
                else
                {
                    HttpContext.Current.Session[UIPermissionKey] = uiPermissions = PermissionFactory.Provider.GetUIPermissions(SecurityContext.User);
                }
                action = action.ToLower();
                return uiPermissions.Count(m => !string.IsNullOrEmpty(m.Code) && m.Code.ToLower() == action) > 0;
            }
            else
            {
                return false;
            }
        }
  
        /// <summary>
        /// 当前是否有访问某个url的权限
        /// url为空时，检测当前url
        /// </summary>
        /// <param name="url">要检测的url</param>
        /// <returns></returns>
        public bool HasUrlGrant(string url = "")
        {
            IEnumerable<Permission.UrlPermission> denyUrlPermissions;

            if (HttpContext.Current.Session == null)
            {
                return true;
            }

            if (HttpContext.Current.Session[UrlPermissionKey] != null)
            {
                denyUrlPermissions = (IEnumerable<Permission.UrlPermission>)HttpContext.Current.Session[UrlPermissionKey];
            }
            else
            {
                denyUrlPermissions = PermissionFactory.Provider.GetActUrlPermissions();
                if (IsLogin)
                {
                    denyUrlPermissions = denyUrlPermissions.Except(PermissionFactory.Provider.GetUrlPermissions(SecurityContext.User), new UrlPermissionComparer());
                }
                HttpContext.Current.Session[UrlPermissionKey] = denyUrlPermissions;
            }

            if (string.IsNullOrEmpty(url))
            {
                url = HttpContext.Current.Request.Url.LocalPath;
            }
            url = url.TrimStart('/').ToLower();

            var result = denyUrlPermissions.Count(m => url.StartsWith(m.Url.TrimStart('/').ToLower())) == 0;
            
            return result;
        }

        public string GetDataRuleCondition(string code)
        {
            IDictionary<string, string> dataRules;
            if (HttpContext.Current.Session == null || SecurityContext.User == null)
                return "";

            if (HttpContext.Current.Session[DataRuleKey] == null)
            {
                HttpContext.Current.Session[DataRuleKey] = dataRules = DataRuleFactory.Provider.GetDataRules(SecurityContext.User);
            }
            else
            {
                dataRules = (IDictionary<string, string>)HttpContext.Current.Session[DataRuleKey];
            }
            if (dataRules.ContainsKey(code))
                return dataRules[code];
            else
                return "";
        }

        #endregion

        #region 属性

        /// <summary>
        /// 是否登录状态
        /// </summary>
        public bool IsLogin
        {
            get
            {
                return HttpContext.Current.User.Identity != null &&
                    HttpContext.Current.User.Identity.IsAuthenticated;
            }
        }

        #endregion

        protected virtual void RemovePromissionSession()
        {
            HttpContext.Current.Session.Remove(UIPermissionKey);
            HttpContext.Current.Session.Remove(UrlPermissionKey);
            HttpContext.Current.Session.Remove(DataRuleKey);
        }

        #region

        /// <summary>
        /// 是否需要加密
        /// </summary>
        private bool NeedEncrypt
        {
            get
            {
                string encryptPassword = System.Configuration.ConfigurationManager.AppSettings["EncryptPassword"];
                return !string.IsNullOrEmpty(encryptPassword) && encryptPassword.ToLower() == "true";
            }
        }

        /// <summary>
        /// 密码加密
        /// </summary>
        /// <param name="password">密码</param>
        /// <returns></returns>
        private string Encrypt(string password)
        {
            var md5 = System.Security.Cryptography.MD5.Create();
            byte[] md5Hash = md5.ComputeHash(Encoding.UTF8.GetBytes(password));
            md5.Clear();
            StringBuilder strBuilder = new StringBuilder();
            foreach (var item in md5Hash)
            {
                strBuilder.Append(item.ToString("x2"));
            }
            return strBuilder.ToString();
        }

        /// <summary>
        /// 保存用户ticket到cookie
        /// </summary>
        /// <param name="user"></param>
        private void SetAuthCookie(IUser user)
        {
            var userData = (new System.Web.Script.Serialization.JavaScriptSerializer()).Serialize(user);
            FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(1, user.LoginId, DateTime.Now, DateTime.Now.Add(FormsAuthentication.Timeout), true, userData);
            string cookieValue = FormsAuthentication.Encrypt(ticket);
            HttpCookie cookie = new HttpCookie(FormsAuthentication.FormsCookieName, cookieValue);
            cookie.HttpOnly = true;
            cookie.Secure = FormsAuthentication.RequireSSL;
            cookie.Domain = FormsAuthentication.CookieDomain;
            cookie.Path = FormsAuthentication.FormsCookiePath;
            HttpContext.Current.User = user;
            // 写Cookie
            HttpContext.Current.Response.Cookies.Remove(cookie.Name);
            HttpContext.Current.Response.Cookies.Add(cookie);
        }

        #endregion

    }
}